/*
Copyright (c) 2020-2022, Huawei Technologies Co., Ltd
 All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

* Description: 3D图表可视化插件界面类
*/
#include "ui_slt_widget.h"
#include <ros/ros.h>

namespace chart_plugin {
const QString MAIN_WIDGET_STYLE_SHEET = "#scrollAreaWidgetContents,#widget\n{\nbackground-color: rgb(20, 21, 24);\n}";
const QString SCROLLAREA_WIDGET_STYLE_SHEET = "QPushButton{background-color:transparent;"
    "color:rgb(255,255,255);border:none;text-align:left;}\nQPushButton::checked{border:1px solid white;}";
const QString RESTORE_BUTTON_STYLE_SHEET = "QPushButton{background-color:transparent;color:rgb(255,255,255);"
    "border:none;}\nQPushButton::pressed{border:1px solid white;}\nQToolTip{background-color:rgb(250,250,210);}";
const int32_t WIDGET_WIDTH = 560;
const int32_t WIDGET_HEIGHT = 320;
const int32_t WIDGET_MIN_WIDTH = 320;
const int32_t WIDGET_MIN_HEIGHT = 260;
const int32_t WIDGET_MATHGL_MIN_WIDTH = 240;
const int32_t WIDGET_MATHGL_MIN_HEIGHT = 120;

const int32_t BUTTON_POSITION_X = 10;
const int32_t BUTTON_POSITION_Y = 10;
const int32_t BUTTON_WIDTH = 75;
const int32_t BUTTON_HEIGHT = 20;

const int32_t GRIDLAYOUT_PACING = 5;
const int32_t GRIDLAYOUT_COUTENTS_MARGINS_LEFT = 4;
const int32_t GRIDLAYOUT_COUTENTS_MARGINS_TOP = 2;
const int32_t GRIDLAYOUT_COUTENTS_MARGINS_RIGHT = 4;
const int32_t GRIDLAYOUT_COUTENTS_MARGINS_BOTTOM = 2;

const int32_t VERTICALL_LAYOUT_STRETCH_MATHGL = 10;
const int32_t VERTICALL_LAYOUT_STRETCH_SCROLLAREA = 1;

QMathGL *UiSltWidget::GetQMathGl() const
{
    return qMathGl;
}

QWidget *UiSltWidget::GetScrollAreaWidgetContents() const
{
    return scrollAreaWidgetContents;
}

QGridLayout *UiSltWidget::GetGridLayout() const
{
    return gridLayout;
}

QPushButton *UiSltWidget::GetRestoreButton() const
{
    return restoreButton;
}

void UiSltWidget::SetupWidgetUi(QWidget &widget)
{
    if (widget.objectName().isEmpty()) {
        widget.setObjectName(QStringLiteral("widget"));
    }
    widget.resize(WIDGET_WIDTH, WIDGET_HEIGHT);
    widget.setMinimumSize(QSize(WIDGET_MIN_WIDTH, WIDGET_MIN_HEIGHT));
    widget.setStyleSheet(MAIN_WIDGET_STYLE_SHEET);
}

void UiSltWidget::SetupVerticalLayoutUi(QVBoxLayout &verticalLayout)
{
    verticalLayout.setSpacing(0); // 设置布局器内部元素无间距
    verticalLayout.setObjectName(QStringLiteral("verticalLayout"));
    verticalLayout.setContentsMargins(0, 0, 0, 0); // 设置布局器边框为0
}

void UiSltWidget::SetupWidgetMathGlUi(QWidget &widgetMathGl)
{
    widgetMathGl.setObjectName(QStringLiteral("widgetMathGl"));
    widgetMathGl.setMinimumSize(QSize(WIDGET_MATHGL_MIN_WIDTH, WIDGET_MATHGL_MIN_HEIGHT));
    qMathGl = new MathGL(&widgetMathGl);

    qMathGl->setObjectName(QStringLiteral("qMathGl"));
    qMathGl->setStyleSheet(QStringLiteral("background-color: rgb(20, 21, 24);"));
    restoreButton = new QPushButton(qMathGl);

    restoreButton->setObjectName(QStringLiteral("restoreButton"));
    restoreButton->setGeometry(QRect(BUTTON_POSITION_X, BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT));

    QIcon icon;
    icon.addFile(":/icons/Restore.png");
    restoreButton->setIcon(icon);
    restoreButton->setText(QApplication::translate("Widget", "Restore", Q_NULLPTR));
    restoreButton->setStyleSheet(RESTORE_BUTTON_STYLE_SHEET);
    restoreButton->setCheckable(true);
    restoreButton->setToolTip("Restore zoom and rotation to default values");
}

void UiSltWidget::SetupScrollAreaUi(QScrollArea &scrollArea)
{
    scrollArea.setObjectName(QStringLiteral("scrollArea"));
    scrollArea.setFrameShape(QFrame::NoFrame);
    scrollArea.setLineWidth(1); // 设置边框线宽值为1
    scrollArea.setWidgetResizable(true);
    scrollAreaWidgetContents = new QWidget(&scrollArea);

    scrollAreaWidgetContents->setObjectName(QStringLiteral("scrollAreaWidgetContents"));
    scrollAreaWidgetContents->setStyleSheet(SCROLLAREA_WIDGET_STYLE_SHEET);
    gridLayout = new QGridLayout(scrollAreaWidgetContents);

    gridLayout->setSpacing(GRIDLAYOUT_PACING);
    gridLayout->setObjectName(QStringLiteral("gridLayout"));
    gridLayout->setContentsMargins(GRIDLAYOUT_COUTENTS_MARGINS_LEFT, GRIDLAYOUT_COUTENTS_MARGINS_TOP,
        GRIDLAYOUT_COUTENTS_MARGINS_RIGHT, GRIDLAYOUT_COUTENTS_MARGINS_BOTTOM);

    scrollArea.setWidget(scrollAreaWidgetContents);
}

void UiSltWidget::SetupUi(QWidget *widget)
{
    if (widget == nullptr) {
        ROS_ERROR("The input parameter widget is nullptr.");
        return;
    }

    SetupWidgetUi(*widget);
    verticalLayout = new QVBoxLayout(widget);

    SetupVerticalLayoutUi(*verticalLayout);
    widgetMathGl = new QWidget(widget);

    SetupWidgetMathGlUi(*widgetMathGl);
    verticalLayout->addWidget(widgetMathGl);
    scrollArea = new QScrollArea(widget);

    SetupScrollAreaUi(*scrollArea);
    verticalLayout->addWidget(scrollArea);
    // 设置Mathgl窗口拉伸比例系数
    verticalLayout->setStretch(0, VERTICALL_LAYOUT_STRETCH_MATHGL);
    // 设置滚动区域窗口拉伸比例系数
    verticalLayout->setStretch(1, VERTICALL_LAYOUT_STRETCH_SCROLLAREA);
}

void chart_plugin::MathGL::wheelEvent(QWheelEvent *event)
{
    if(!enableWheel) {
        event->ignore();
        return;
    }

    if(rotate) {
        const float scaleSize = -0.001;
        // 2代表取平均值
        mreal exponential = exp(scaleSize * event->delta()) / 2;
        mreal diff = (y2 - y1) * exponential;
        // 2代表取平均值
        mreal sum = (y2 + y1) / 2;
        y1 = sum - diff;
        y2 = sum + diff;
        diff = (x2 - x1) * exponential;
        // 2代表取平均值
        sum = (x2 + x1) / 2;
        x1 = sum - diff;
        x2 = sum + diff;
        refresh();
        event->accept();
        return;
    }
    const float scaleSize = 0.001;
    // 2代表取平均值
    mreal exponential = exp(scaleSize * event->delta()) / 2;
    mreal diff = (ay2 - ay1) * exponential;
    // 2代表取平均值
    mreal sum = (ay2 + ay1) / 2;
    ay1 = sum - diff;
    ay2 = sum + diff;
    diff = (ax2 - ax1) * exponential;
    // 2代表取平均值
    sum = (ax2 + ax1) / 2;
    ax1 = sum - diff;
    ax2 = sum + diff;
    mgl_zoom_axis((HMGL)gr, ax1, ay1, 0, 0, ax2, ay2, 0, 0);
    update();
    event->accept();
}

void MathGL::mousePressEvent(QMouseEvent *event)
{
    posX = event->x();
    posY = event->y();
    x = event->x();
    y = event->y();
    QMathGL::mousePressEvent(event);
}

void MathGL::mouseMoveEvent(QMouseEvent *event)
{
    if(!rotate || !(event->buttons() & Qt::LeftButton)) {
        QMathGL::mouseMoveEvent(event);
        return;
    }

    int32_t pi = 360;
    int32_t halfPi = 180;
    // 2代表取高度的一半
    int32_t halfHeight = height() / 2;
    x = event->x();
    y = event->y();

    tet += static_cast<int32_t>(halfPi * (posY - y) / sqrt(mreal(width() * height())));
    if (tet > halfPi) {
        tet -= pi;
    } else if (tet < -halfPi) {
        tet += pi;
    }

    if (event->y() < halfHeight) {
        phi -= static_cast<int32_t>(halfPi * (posX - x) / sqrt(mreal(width() * height())));
    } else if (event->y() > halfHeight) {
        phi += static_cast<int32_t>(halfPi * (posX - x) / sqrt(mreal(width() * height())));
    }

    if (phi > halfPi) {
        phi -= pi;
    } else if (phi < -halfPi) {
        phi += pi;
    }
    emit tetChanged(static_cast<int32_t>(tet));
    emit phiChanged(static_cast<int32_t>(phi));
    posX = x;
    posY = y;
    refresh();
}

void MathGL::mouseReleaseEvent(QMouseEvent *event) 
{
    if ((event->button() & Qt::LeftButton) && enableMouse) {
        if (zoom) {
            posX = x;
            posY = y;
        }
    }
    QMathGL::mouseReleaseEvent(event);
}
} //  namespace chart_plugin
